﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Labthink.PCSoft.UniversalHost4.Instrument.Model;
using Labthink.PCSoft.UniversalHost4.Utility;
using Microsoft.Research.DynamicDataDisplay;
using Microsoft.Research.DynamicDataDisplay.DataSources;
using NLog;
using SystemSettings;
using Labthink.PCSoft.UniversalHost4.DataAccess;
using Labthink.PCSoft.UniversalHost4.Instrument.Forms;
using Labthink.PCSoft.UniversalHost4.Model;
using Labthink.PCSoft.UniversalHost4.Model.User;
using System.Collections.ObjectModel;

namespace Labthink.PCSoft.UniversalHost4.UserControls
{
    public partial class UcDashboard
    {
        private bool _loaded;
        private readonly Logger _logger = LogManager.GetCurrentClassLogger();
        private NotifyManager _notify;
        private ObservableDataSource<double> _dataTime = new ObservableDataSource<double>();
        private ObservableDataSource<double> _dataTemp = new ObservableDataSource<double>();
        private ObservableDataSource<double> _dataHumid = new ObservableDataSource<double>();

        private LineGraph _flowLgTemp, _flowLgHumid;
        public Func<double, string> AxisFormatterPressure { get; set; }

        public Func<double, string> AxisFormatterTime { get; set; }
        public double AxisStep { get; set; }

        public double AxisUnit { get; set; }

        private readonly TestFlow _flow;

        private int _yMin;
        private int _yMax;

        /// <summary>
        /// 当前一组试验已完成件数
        /// </summary>
        //private int SubTestId { get; set; }

        private ObservableCollection<ListData> ltDatas = new ObservableCollection<ListData>(); //实时数据
        //private List<ListData> ltDataBuffer = new List<ListData>(); //实时数据缓冲
        List<FullData> datas, ps;

        public UcDashboard()
        {
            InitializeComponent();
            DataContext = this;
            SerialPortHelper.OnReceiveParameterHandler += OnReceiveParameterHandler;
            //SerialPortHelper.OnTestStatusChangedHandler += OnTestStatusChangedHandler;
            SerialPortHelper.OnReceiveRealtimeDataHandler += OnReceiveRealtimeDataHandler;
            SerialPortHelper.OnReceiveResultHandler += OnReceiveResultHandler;
            SerialPortHelper.OnTestStartedHandler += OnTestStartedHandler;
            //SerialPortHelper.OnTestStopHandler += OnTestStopHandler;
            Common.LoginSuccess += OnLoginLoginSuccess;

            AxisFormatterTime = value => value.ToString("f1");
            AxisFormatterPressure = value => value.ToString("f1");

            AxisStep = TimeSpan.FromSeconds(1).Ticks;
            AxisUnit = TimeSpan.TicksPerSecond;
            _flow = new TestFlow();
        }

        private void OnLoginLoginSuccess(object sender, UserAndPermission e)
        {
            _logger.Debug("OnLoginLoginSuccess");
            LoadPer();
            _loadD3();
            var frm = States.Instance.FrmSystemSet;
            frm.ReConfigPermission();

            var frm1 = States.Instance.FrmParamSet;
            frm1.ReConfigPermission();
            datas = CurrentRepository.DataInfo(1);
        }

        private void UcDashboard_OnLoaded(object sender, RoutedEventArgs e)
        {
            if (DesignerProperties.GetIsInDesignMode(this))
            {
                return;
            }

            if (_loaded)
                return;

            LoadPer();
            _loaded = true;
            BtnSaveTest.IsEnabled = false;
            _loadD3();
            _notify = NotifyManager.InstanceManager(Application.Current.MainWindow);
            bool isOpened = SerialPortHelper.OpenSerialPort();
            if (isOpened)
            {
                States.Instance.Main.LblSerialPortName.Content = Common.ComInfo.PortName;
                States.Instance.Main.LblSerialPortStatus.Content = LanguageManager.GetLanguageValue("SerialPortOpened");
                ConfigAndSettings.SetComInfo(Common.ComInfo);
            }
            else
            {
                States.Instance.Main.LblSerialPortName.Content = Common.ComInfo.PortName;
                States.Instance.Main.LblSerialPortStatus.Content = LanguageManager.GetLanguageValue("SerialPortInUse");
                States.Instance.Main.LblSerialPortStatus.Foreground = new SolidColorBrush(Colors.Red);
                States.Instance.Main.LblSerialPortStatus.Background = new SolidColorBrush(Colors.Yellow);
            }
            dtgResult.ItemsSource = ltDatas;
            _logger.Debug("UcDashboard_OnLoaded");
        }

        private void LoadPer()
        {
            //if (Common.Permissions.All(p => p.Code != "Per_SaveTest".Clear()))
            //{
            //    BtnSaveTest.Visibility = Visibility.Collapsed;
            //}
            //else
            //{
            //    BtnSaveTest.Visibility = Visibility.Visible;
            //}

            if (Common.Permissions.All(p => p.Code != "ParamSet".Clear()))
            {
                BtnParamSet.Visibility = Visibility.Collapsed;
            }
            else
            {
                BtnParamSet.Visibility = Visibility.Visible;
            }

            if (Common.Permissions.All(p => p.Code != "Per_System".Clear()))
            {
                BtnSystemSet.Visibility = Visibility.Collapsed;
            }
            else
            {
                BtnSystemSet.Visibility = Visibility.Visible;
            }
        }

        private void BtnParamSet_Click(object sender, RoutedEventArgs e)
        {
            var frm = States.Instance.FrmParamSet;
            frm.ShowDialog(States.Instance.MainWindow);
            /*
            if (frm.SetOrCancel)
            {
                //UpdateTestModeText();
                UpdatePlotRegion();
            }

            if (frm.SetOrCancel == true && Common.TestStatus == TestStatus.PartialSaved)
            {
                UpdatePlotRegion();
                SaveTest();
                ResetStatics();

                Common.TestStatus = TestStatus.FullySaved;
                var log = LanguageManager.GetLanguageValue("OP-TestSave", TestId);
                LogRepository.AddLog(log, "TEST");
            }
            */
        }

        /// <summary>
        /// 手动结束本组试验并保存
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnSaveTest_Click(object sender, RoutedEventArgs e)
        {
            if (Common.TestStatus != TestStatus.FullySaved)
            {
                Common.TestStatus = TestStatus.FullySaved;
                //TbStage.Text = LanguageManager.GetLanguageValue("Flow-AllTestEnd");
                SaveTest();
                //UpdatePlotRegion();
                //SerialPortHelper.OnTestStatusChanged(TestStatus.FullySaved);

                var log = LanguageManager.GetLanguageValue("OP-TestSaveByHand", Common.nTestNo);
                LogRepository.AddLog(log, "TEST");
                Common.nDataId = 0;
                BtnSaveTest.IsEnabled = false;
            }
            else
            {
                MessageBox.Show(LanguageManager.GetLanguageValue("OP-TestSaved", Common.nTestNo));
            }
        }

        private void BtnSystemSet_Click(object sender, RoutedEventArgs e)
        {
            var frm = States.Instance.FrmSystemSet;
            frm.ShowDialog(States.Instance.MainWindow);
        }

        //private void UpdateTopSampleNo()
        //{
        //    SampleCount = Common.CurrentParam.Params.Get(1120).Value.ToInt();
        //    TbSubTestId.Text = $"{(SubTestId == 0 ? "-" : SubTestId.ToString())}/{SampleCount}";
        //}

        private void Plotter_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            var plotter = sender as ChartPlotter;
            plotter?.FitToView();
        }

        private void OnTestStartedHandler(object sender, ComStartEventArgs e)
        {
            Dispatcher.Invoke(() =>
                {
                    ltDatas.Clear();
                    Common.nDataId = 0;
                    //BtnStartTest.Content = LanguageManager.GetLanguageValue("StopTest");
                    _loadD3();
                    if (Common.nTestNo != e.TestNo)
                    {
                        Common.nTestNo = e.TestNo; //试验编号 ConfigAndSettings.GetNextTestId();
                    }
                    ps.Single(px => px.DataNo == 1001).Value = Common.nTestNo; //试验编号作为参数，在开始时接收
                    _flow.CreateDb(1, null, 1, Common.nTestNo, DateTime.Now, Common.BaseInfo.Sn); //只有一个数据库模板
                    Common.nTestId = e.TestId; //次数

                    if (Common.unitPressure != "kPa") //非默认单位则修改数据库模板
                    {
                        CurrentRepository.UpdateParamInfoUnit(Common.unitPressure, Common.nDigitPressure, 1030);
                        CurrentRepository.UpdateRtdInfoUnit(Common.unitPressure, Common.nDigitPressure, 2030);
                    }
                    TxtTestNo.Value = e.TestNo.ToString();
                    TxtTestId.Value = e.TestId.ToString();
                    TxtResult.Value = "";
                    BtnSaveTest.IsEnabled = false;

                    LogRepository.AddLog(LanguageManager.GetLanguageValue("OP-TestStart", Common.nTestNo, Common.nTestId), "Test");
                }
            );
        }
        private void OnReceiveParameterHandler(object sender, ComParameterEventArgs e)
        {
            Dispatcher.Invoke(() =>
            {
                //Common.TestStatus = TestStatus.ParameterSet;
                TbCount.Text = Common.nSampleCount.ToString();
                TbInfo.Text = e.SampleInfo;
                TbUpperTemp.Text = e.PmUpperTemp.ToString("F1");
                TbLowerTemp.Text = e.PmLowerTemp.ToString("F1");
                TbPressure.Text = e.PmPressure.ToString($"F{Common.nDigitPressure}");
                TbHsTime.Text = e.PmTime.ToString("F2");
                TbUnitP.Text = Common.unitPressure;
                DgcPressure.Header = LanguageManager.GetLanguageValue("Pressure") + $"({Common.unitPressure})";

                //_loadD3();
                ps = Common.MapToFullData(Common.CurrentParam.Params);
                //ps.Single(px => px.DataNo == 1001).Value = TestNo; //试验编号在开始和结束帧，作为参数处理
                ps.Single(px => px.DataNo == 1010).Value = e.PmUpperTemp;
                ps.Single(px => px.DataNo == 1020).Value = e.PmLowerTemp;
                ps.Single(px => px.DataNo == 1030).Value = e.PmPressure;
                ps.Single(px => px.DataNo == 1040).Value = e.PmTime;
                ps.Single(px => px.DataNo == 1050).Value = Common.nSampleCount;
                ps.Single(px => px.DataNo == 1060).Value = e.SampleInfo;

                if (_flow.CurrentParams.ContainsKey(1)) //Common.TestFlow
                {
                    _flow.CurrentParams[1] = ps;
                }
                else
                {
                    _flow.CurrentParams.Add(1, ps);
                }
                ltDatas.Clear();

            });
        }

        /*
        /// <summary>
        /// 秒数转为“时：分：秒”格式
        /// </summary>
        /// <param name="nSeconds"></param>
        /// <returns></returns>
        private string intToStr(int nSeconds)
        {
            int nHour = (int)nSeconds / 3600;
            int nMinute = (int)nSeconds % 3600 / 60;
            int nSecond = (int)nSeconds % 60;
            string strTime = $"{nHour}:{nMinute:D2}:{nSecond:D2}";
            return strTime;
        }
        private void OnTestStatusChangedHandler(object sender, ComTestStatusEventArgs e)
        {
            Dispatcher?.Invoke(() =>
            {
                if (e.Status == TestStatus.Testing)
                {
                    ltDatas[e.Station - 1].bTesting = true;
                    ltDatas[e.Station - 1].status = LanguageManager.GetLanguageValue("Flow-Testing");
                    ltDatas[e.Station - 1].nDeltaTime = e.deltaTime;
                    ltDatas[e.Station - 1].time = "00:00:00";
                    ltDatas[e.Station - 1].disp = "";
                    TbTime.Text = e.TestId.ToString(); //试验编号
                }
                else if (e.Status == TestStatus.End)
                {
                    //ltDatas[e.Station - 1].bTesting = false;
                    ltDatas[e.Station - 1].status = LanguageManager.GetLanguageValue("Flow-TestEnd");
                }
                else if (e.Status == TestStatus.Abnormal)
                {
                    ltDatas[e.Station - 1].status = LanguageManager.GetLanguageValue("Flow-TestEnd-Abnormally");
                }
                else if (e.Status == TestStatus.FullySaved)
                {
                    // 保存完成后变为Idle状态
                }
            });
        }
        */

        private void OnReceiveRealtimeDataHandler(object sender, ComRealTimeDataEventArgs e)
        {
            var fTime = e.RtTime;
            var fPressure = e.RtPressure;
            var fUpperTemp = e.RtUpperTemp;
            var fLowerTemp = e.RtLowerTemp;
            Dispatcher.Invoke(() =>
            {
                if (Common.TestStatus == TestStatus.ParameterSet) //未收到开始帧
                {
                    ltDatas.Clear();
                    Common.nDataId = 0;
                }
                if (Common.TestStatus != TestStatus.Testing)
                {
                    Common.TestStatus = TestStatus.Testing;
                }
                //BtnStartTest.Content = LanguageManager.GetLanguageValue("StopTest");

                Common.nDataId++;

                //实时曲线
                _dataTime.Collection.Add(fTime);
                _dataTemp.Collection.Add(fUpperTemp);
                _dataHumid.Collection.Add(fLowerTemp);

                datas.Single(d => d.DataNo == 10034).Value = Common.nTestId; //并列试验号即次数
                datas.Single(d => d.DataNo == 2010).Value = fUpperTemp;
                datas.Single(d => d.DataNo == 2020).Value = fLowerTemp;
                datas.Single(d => d.DataNo == 2030).Value = fPressure;
                datas.Single(d => d.DataNo == 2040).Value = fTime;
                _flow.SendTestData(null, 1, Common.nTestNo, datas);

                //ltDatas.Add(new ListData(Common.nDataId, fUpperTemp, fLowerTemp, fTime.ToString("F2"), fPressure.ToString($"F{Common.nDigitPressure}")));
                ltDatas.Add(new ListData(Common.nDataId, fUpperTemp, fLowerTemp, fPressure, fTime));

            });
        }

        private void OnReceiveResultHandler(object sender, ComResultEventArgs e)
        {
            Dispatcher.Invoke(() =>
                {
                    Common.nDataId = 0;
                    if (e.nQualified < 2) //未选择结果则不保存本次数据和结果
                    {
                        var result = CurrentRepository.ResultInfo(1);
                        result.Single(d => d.DataNo == 10034).Value = e.TestId; //试验编号与开始中应相同
                                                                                //result.Single(d => d.DataNo == 3010).Value = e.TestId;
                        result.Single(d => d.DataNo == 3010).Value = e.nQualified;

                        _flow.SendTestResult(null, 1, e.TestNo, result);
                        if (Common.nSampleCount == Common.nTestId) //SendTestResult时会自动保存，当次数到设定件数时可删除内存数据库以便新建。
                        {
                            Common.TestStatus = TestStatus.FullySaved;
                            CurrentRepository.SaveTest(1);
                        }
                    }
                    else //无结果时设备继续试验时试验次数不变，因此不允许保存----设备只提供合格、不合格两项，正常不会无结果。
                    {
                        BtnSaveTest.IsEnabled = false;
                    }

                    TxtTestNo.Value = e.TestNo.ToString();
                    TxtTestId.Value = e.TestId.ToString();
                    TxtResult.Value = Common.arrResult[e.nQualified];

                    var log1 = LanguageManager.GetLanguageValue("OP-TestEnd", Common.nTestNo, Common.nTestId);
                    LogRepository.AddLog(log1, "TEST");
                }
            );
        }

        //private void OnTestStopHandler(object sender, EventArgs e)
        //{
        //    Dispatcher.Invoke(() =>
        //        {
        //BtnStartTest.Content = LanguageManager.GetLanguageValue("StartTest");
        //_finishedCount++;
        //UpdateStatisticsResult();
        //var log = LanguageManager.GetLanguageValue("OP-TestEndByHand", TestId, SubTestId);
        //LogRepository.AddLog(log, "TEST");

        //if (SubTestId >= SampleCount)
        //{
        //    BtnSaveTest.IsEnabled = false;
        //}
        //else
        //{
        //    BtnSaveTest.IsEnabled = true;
        //}
        //            if (Common.TestStatus != TestStatus.FullySaved)
        //            {
        //                Common.TestStatus = TestStatus.FullySaved;
        //                //TbStage.Text = LanguageManager.GetLanguageValue("Flow-AllTestEnd");
        //                IniHelper.Filename = ConfigAndSettings.IniFile;
        //                IniHelper.SectionName = "testConfig";
        //                Common.unitTempParam = IniHelper.GetIni("unit", "°C");
        //                CurrentRepository.UpdateParamInfoUnit(Common.unitTempParam, 10076); //new List<int>() { 2010 }
        //                CurrentRepository.UpdateRtdInfoUnit(Common.unitTemp, 2010); //new List<int>() { 2010 }
        //                SaveTest();
        //                //SerialPortHelper.OnTestStatusChanged(TestStatus.FullySaved);

        //                var log = LanguageManager.GetLanguageValue("OP-TestSave", TestId);
        //                LogRepository.AddLog(log, "TEST");
        //                Common.nTestId = 0;
        //                BtnSaveTest.IsEnabled = false;
        //            }
        //        }
        //    );
        //}
        private void _loadD3()
        {
            _dataTime = new ObservableDataSource<double>();
            _dataTemp = new ObservableDataSource<double>();
            _dataHumid = new ObservableDataSource<double>();

            _dataTime.SetXMapping(x => x);
            _dataTemp.SetYMapping(y => y);
            _dataHumid.SetYMapping(y => y);

            PlotterTH.Legend.LegendLeft = 10;
            PlotterTH.Legend.LegendRight = double.NaN;

            if (_flowLgTemp != null)
            {
                PlotterTH.Children.Remove(_flowLgTemp);
                PlotterTH.Children.Remove(_flowLgHumid);
            }

            var dsTemp = new CompositeDataSource(_dataTime, _dataTemp);
            string yAxisT = LanguageManager.GetLanguageValue("UpCurve") + "(°C)"; //上封头温度曲线;
            _flowLgTemp = PlotterTH.AddLineGraph(dsTemp, Colors.Blue, 1, yAxisT);
            var dsHumid = new CompositeDataSource(_dataTime, _dataHumid);
            string yAxisH = LanguageManager.GetLanguageValue("LowCurve") + "(°C)"; //下封头温度曲线
            _flowLgHumid = PlotterTH.AddLineGraph(dsHumid, Colors.Green, 1, yAxisH);
            //UpdatePlotRegion();
        }

        private void UpdatePlotRegion()
        {
            PlotterTH.Viewport.AutoFitToView = true;
            var restr = new ViewportAxesRangeRestriction();
            if (_dataTime.Collection.Any())
            {
                restr.XRange = new DisplayRange(0, ((int)_dataTime.Collection.Max() / 10 + 1) * 10.0);
            }
            else
            {
                restr.XRange = new DisplayRange(0, 10);
            }

            restr.YRange = new DisplayRange(0, 100);
            PlotterTH.Viewport.Restrictions.Clear();
            PlotterTH.Viewport.Restrictions.Add(restr);
        }

        /// <summary>
        /// 保存当前试验，新开一组
        /// 1、手动点击保存时
        /// 2、达到设定的件数时
        /// 3、重新设置参数后
        /// </summary>
        private void SaveTest()
        {
            CurrentRepository.SaveTest(1);
            BtnSaveTest.IsEnabled = false;
        }

        private void _triggerButtonsStatus(bool status)
        {
            IsEnabled = status;
            Loading.Visibility = status ? Visibility.Collapsed : Visibility.Visible;
        }

        private void BtnLog_Click(object sender, RoutedEventArgs e)
        {
            var frm = new FrmOpLog(); //操作日志
            frm.ShowDialog(Application.Current.MainWindow);
        }

        private void BtnReset_Click(object sender, RoutedEventArgs e)
        {
            _loadD3();
            Common.nDataId = 0; //工位

            ltDatas.Clear();
            BtnSaveTest.IsEnabled = false;
            //Common.ltResut.Clear();
        }

        private void BtnScheme_Click(object sender, RoutedEventArgs e)
        {
            //var frm = new FrmSchemeList();
            //frm.ShowDialog(Application.Current.MainWindow);
            var frm = new FrmSerialSet(); //串口设置
            frm.ShowDialog(Application.Current.MainWindow);
        }
    }
}
